package com.life.controller;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;

import com.life.constants.Constants;
import com.life.model.LifeModel;
import com.life.statistics.StatisticStruct;
import com.life.statistics.StatisticsElement;
import com.life.utils.BoardLocationStruct;
import com.life.utils.ClusterStruct;
import com.life.utils.DialogUtil;
import com.life.utils.LoggerUtil;
import com.life.utils.StatisticsUtil;
import com.life.view.AbstractAdapter;
import com.life.view.GraphAdapter;
import com.life.view.ProgressAdapter;

public class StatisticsController extends AbstractController
{

    AbstractAdapter generateStatAdapter = null;

    ProgressAdapter generateProgressAdapter = null;

    AbstractAdapter listAdapter = null;

    AbstractAdapter tabbedPaneAdapter = null;

    AbstractAdapter playAdapter = null;

    AbstractAdapter pauseAdapter = null;
    
    AbstractAdapter showGraphAdapter = null;

    AbstractAdapter graphOptionAdapter = null;
    
    AbstractAdapter mouseAdapter = null;
    
    AbstractAdapter cellInfoAdapter = null;
    
    AbstractAdapter drawingAdapter = null;
    
    AbstractAdapter highlightClustersAdapter = null;
    
    AbstractAdapter sliderAdapter = null;

    DecimalFormat decimalFormatter = new DecimalFormat("#.00");

    StatisticStruct results = null;
    ArrayList graphTypes = new ArrayList();
    
    boolean highlighted = false;
    
    boolean generated = false;
    
    public StatisticsController(LifeModel model,
	    ArrayList<AbstractAdapter> adapterList)
    {
	super(model, adapterList);
	generateStatAdapter = adapterList.get(0);
	generateProgressAdapter = (ProgressAdapter) adapterList.get(1);
	listAdapter = adapterList.get(2);
	tabbedPaneAdapter = adapterList.get(3);
	playAdapter = adapterList.get(4);
	pauseAdapter = adapterList.get(5);
	showGraphAdapter =  adapterList.get(6);
	graphOptionAdapter = adapterList.get(7);
	mouseAdapter = adapterList.get(8);
	cellInfoAdapter = adapterList.get(9);
	drawingAdapter = adapterList.get(10);
	highlightClustersAdapter = adapterList.get(11);
	sliderAdapter = adapterList.get(12);
	
	
	graphTypes.add(Constants.LIFE_OVER_GENERATIONS);
	graphTypes.add(Constants.DEATH_OVER_GENERATIONS);
	graphTypes.add(Constants.CHANGE_IN_BIRTH);
	
	
	generateStatAdapter.setEnabled(false);
	generateProgressAdapter.setVisible(false);
	mouseAdapter.setEnabled(false);
    }

    @Override
    public void doUpdate(AbstractAdapter source, Object data)
    {
	if (generateStatAdapter == source)
	{
	    generated = true;
	    generateStatistics();
	}

	if (playAdapter == source)
	{
	    tabbedPaneAdapter.setVisible(false);
	    generateStatAdapter.setEnabled(false);
	    mouseAdapter.setEnabled(false);
	    generated = false;
	    
	   reset();
	}

	if (pauseAdapter == source)
	{
	    generateStatAdapter.setEnabled(true);
	}
	
	if(showGraphAdapter == source)
	{
	    generateGraph();
	}
	
	if(mouseAdapter == source)
	{
	    updateCellInfo((BoardLocationStruct)data);
	}
	
	if(sliderAdapter == source && generated)
	{
	    processHighlight();
	    
	}
	
	if(highlightClustersAdapter == source && !highlighted)
	{
	   highlighted = true;
	   processHighlight();
	}		
	else if(highlightClustersAdapter == source && highlighted)
	{
	    highlighted = false;
	    processHighlight();
	}
    }
    
    public void processHighlight()
    {
	if(!highlighted)
	{
	    highlightCells();
	}
	
	if(highlighted)
	{
	    highlightClusters();
	}
    }
    
    public void reset()
    {
	HashMap hash = new HashMap();
	hash.put(Constants.RESET, Constants.RESET);
	drawingAdapter.set(hash);
    }
    
    public void highlightClusters()
    {
	HashMap hash =  new HashMap();
	hash.put(Constants.SHOW_CLUSTERS,StatisticsUtil.calculateClusters(results));
	drawingAdapter.set(hash);
    }
    
    public void highlightCells()
    {
	HashMap hash =  new HashMap();
	hash.put(Constants.SHOW_STATISTICS,results);
	drawingAdapter.set(hash);
    }
    
    public void updateCellInfo( BoardLocationStruct data)
    {
	try{
	    
	ArrayList <String>cellInfo = new ArrayList<String>();
	
	/* get data for cell */
	if(theModel.isValid(data.boardX+1,data.boardY+1) && 
		results.elements.length>data.boardX && 
		results.elements[0].length>data.boardY)
	{
	    
	StatisticsElement theElement = results.elements[data.boardX][data.boardY];
	 
	String lifeCount = "Total Life: " + theElement.getSum();
	String lifeMean = "Percent of Cell being alive: " + decimalFormatter.format(theElement.getMean() * 100) + "%";
	String lifeStd = "Life Std.Dev: " + theElement.getStdDev();
	
	cellInfo.add(lifeCount);
	cellInfo.add(lifeMean);
	cellInfo.add(lifeStd);
	
	cellInfoAdapter.set(cellInfo);
	}
	}
	catch(Exception ex)
	{
	    System.out.println("Error finding cell info");
	}
	
    }
    
    
    public void generateGraph()
    {
	String selectedGraph = graphOptionAdapter.get().toString();

	
	if(selectedGraph.equals(Constants.LIFE_OVER_GENERATIONS))
	{
	    generateGraph(Constants.LIFE_OVER_GENERATIONS,"Generations","# Living Cells",StatisticsUtil.calculateLifeGraph(results));
	}
	else if(selectedGraph.equals(Constants.DEATH_OVER_GENERATIONS))
	{
	    generateGraph(Constants.DEATH_OVER_GENERATIONS,"Generations","# Dead Cells",StatisticsUtil.calculateDeathGraph(results));
	}
	else if(selectedGraph.equals(Constants.CHANGE_IN_BIRTH))
	{
	    generateGraph(Constants.CHANGE_IN_BIRTH,"Generations","# Birth Cells",StatisticsUtil.calculateBirthChangeGraph(results));
	}
	
    }
    
    public void generateGraph(String title,String domainLabel,String rangeLabel, HashMap<String,ArrayList>graphResults)
    {
	
	GraphAdapter adapter = new GraphAdapter();
	adapter.setChartTitle(title);
	adapter.setDomainAxisLabel(domainLabel);
	adapter.setRangeAxisLabel(rangeLabel);
	
	adapter.set(graphResults);
    }

    public void generateStatistics()
    {
	generateProgressAdapter.setVisible(true);
	Thread newThread = new Thread()
	{
	    public void run()
	    {
		try
		{
		results = StatisticsUtil.calculateStatistics(
			LoggerUtil.getModels(), generateProgressAdapter
				.getProgressIndicator());

		generateProgressAdapter.setVisible(false);

		displayResults(results);
		tabbedPaneAdapter.setVisible(true);
		graphOptionAdapter.set(graphTypes);
		
		ArrayList<String>cellInfoData= new ArrayList<String>();
		
		cellInfoData.add("Mouse over cells to find cell information");
		cellInfoData.add("Only grayed-out cells contain data");
		
		mouseAdapter.setEnabled(true);
		
		cellInfoAdapter.set(cellInfoData);
		
		processHighlight();
	    }
		catch(java.lang.OutOfMemoryError error)
		{
		    DialogUtil.showMessageDialog(Constants.SYSTEM_RESOURCES_ERROR_MESSAGE);
		} 
		catch(java.lang.StackOverflowError error)
		{
		    DialogUtil.showMessageDialog(Constants.SYSTEM_RESOURCES_ERROR_MESSAGE);
		}
	    }
	};
	newThread.start();
    }

    public void displayResults(StatisticStruct struct)
    {
	ArrayList<String> reports = struct.getReportList();
	listAdapter.set(reports);

    }
}
